﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using WebRamosUC.Models;
using System.IO;

namespace XmlCursosUploader
{
    class Program
    {
        [STAThread]
        static void Main(string[] args)
        {
            //////////////
            // HACK PARA PODER USAR LA DB QUE ESTA EN WEBRAMOSUC
            var dinfo = new DirectoryInfo(Environment.CurrentDirectory);
            string rootPath = dinfo.Parent.Parent.Parent.FullName;
            AppDomain.CurrentDomain.SetData("DataDirectory", rootPath);
            //////////////

            Console.ForegroundColor = ConsoleColor.Green;
            Console.Title = "XML Cursos Uploader";

            Console.WriteLine("Bienvenido al uploader de cursos.\n");
            Console.WriteLine("Ingrese: \n'upload' para subir cursos \n'destroy' para borrar la BD \n'exit' para salir.");
            Console.Write("> ");

            switch (Console.ReadLine())
            {
                case "upload":
                    UploadCursos();
                    break;
                case "destroy":
                    DestroyDB();
                    break;
                case "exit":
                    return;
                default:
                    Console.WriteLine("Comando invalido, saliendo...");
                    return;
            }
        }

        /// <summary>
        /// Borra todas las entradas de la BD.
        /// </summary>
        private static void DestroyDB()
        {
            Console.WriteLine("\nSeguro que desea BORRAR TODOS LOS DATOS de la BD? (Incluye tabla Usuarios, Recomendaciones, etc.)");
            Console.Write("(y/n) ");

            if (Console.ReadLine().ToLower() == "y")
            {
                WebRamosUCDataContext db = new WebRamosUCDataContext();
                db.ExecuteCommand("EXEC sp_msforeachtable \"ALTER TABLE ? NOCHECK CONSTRAINT all\"");
                db.ExecuteCommand("EXEC sp_MSForEachTable \"DELETE FROM ?\"");
                db.ExecuteCommand("EXEC sp_msforeachtable \"ALTER TABLE ? WITH CHECK CHECK CONSTRAINT all\"");
                try
                {
                    db.ExecuteCommand("EXEC sp_MSForEachTable \"DBCC CHECKIDENT('?', RESEED, 0)\"");
                }
                catch (Exception e)
                {
                    Console.WriteLine("\nAl cambiar el SEED a las tablas, resulto el siguiente mensaje:");
                    Console.WriteLine("Generalmente no hay problemas.");
                    Console.ForegroundColor = ConsoleColor.Yellow;
                    Console.WriteLine(e.Message);
                    Console.ForegroundColor = ConsoleColor.Green;
                }

                Console.WriteLine("Borrado exitosamente las entradas de la BD. Saliendo...");
                Console.ReadKey();
            }
        }

        /// <summary>
        /// Pregunta al usuario por la ruta del XML cursos, y la abre.
        /// </summary>
        private static void UploadCursos()
        {
            Console.WriteLine("\nIngrese la ruta al archivo (o ENTER para abrir un OpenFileDialog).");
            Console.Write("> ");
            string ruta = Console.ReadLine();

            if (ruta == "" || ruta == "open")
            {
                //Abrimos el OpenFileDialog
                var dialog = new System.Windows.Forms.OpenFileDialog();
                dialog.Filter = "Archivos XML|*.xml";
                dialog.RestoreDirectory = true;

                var dialogResult = dialog.ShowDialog();
                if (dialogResult == System.Windows.Forms.DialogResult.OK)
                {
                    ruta = dialog.FileName;
                    Console.WriteLine("Archivo: " + ruta);
                }
                else
                    return;
            }

            //Abrimos archivo XML
            XmlDocument doc = new XmlDocument();
            doc.Load(ruta);
            ParseXmlCursos(doc);
        }

        /// <summary>
        /// Parsea el XML y lo sube a la DB.
        /// TODO:
        /// * Actualizar el contenido de los semestres si ya existen.
        /// * Agregar requisitos del curso
        /// * Agregar ptje de cortes.
        /// * Asignar correo, depto., etc. al profesor
        /// </summary>
        private static void ParseXmlCursos(XmlDocument doc)
        {
            int ramosTotal = 0;               //debug
            DateTime start = DateTime.Now;  //debug

            //Creo el repo para agregar un periodo
            WebRamosUCDataContext db = new WebRamosUCDataContext();
            RepositorioPeriodo repoPeriodo = new RepositorioPeriodo(db);

            XmlElement root = doc.DocumentElement;

            //Vemos si el periodo existe:
            string periodoStr = root.GetAttribute("Periodo");
            int anio = Int32.Parse(periodoStr.Substring(0, 4));
            int sem = Int32.Parse(periodoStr.Substring(5, 1));
            Periodo periodo = repoPeriodo.GetPeriodo(anio, sem);
            //No existe! Creamos un nuevo periodo.
            if (periodo == null)
            {
                periodo = new Periodo();
                periodo.Anio = anio;
                periodo.Semestre = sem;
                repoPeriodo.AddPeriodo(periodo);
            }

            //Guardo periodo.
            db.SubmitChanges();

            //Instancias del repo para toda la transaccion de ramos:
            var repoCursos = new RepositorioCurso(db);
            var repoFacultad = new RepositorioFacultad(db);
            var repoProfesor = new RepositorioProfesor(db);

            //Recorremos todos los Cursos del XML
            foreach (XmlNode ramoNode in root)
            {
                ramosTotal++;
                // Instancias de repo. se crean por cada ramo
                //db = new WebRamosUCDataContext();
                //repoPeriodo = new RepositorioPeriodo(db);
                //var repoCursos = new RepositorioCurso(db);
                //var repoFacultad = new RepositorioFacultad(db);
                //var repoProfesor = new RepositorioProfesor(db);


                string sigla = ramoNode["Sigla"].InnerText;

                Curso curso = repoCursos.GetCurso(sigla);
                //No existe el curso; creamos uno nuevo.
                if (curso == null)
                {
                    curso = new Curso();

                    curso.Sigla = sigla;
                    curso.Creditos = Int32.Parse(ramoNode["Creditos"].InnerText);
                    curso.Descripcion = ramoNode["Descripcion"].InnerText;
                    curso.NombreCurso = ramoNode["Nombre"].InnerText;
                    curso.Requisitos = "No disponible";              //TODO!! Agregar requisitos despues!!
                    curso.UrlPrograma = ramoNode["UrlPrograma"].InnerText;

                    string facNombre = ramoNode["Facultad"].InnerText;
                    Facultad facultad = repoFacultad.GetFacultad(facNombre);
                    //No existe la facultad; creamos una nueva.
                    if (facultad == null)
                    {
                        facultad = new Facultad();
                        facultad.Nombre = facNombre;
                        repoFacultad.AddFacultad(facultad);
                        db.SubmitChanges();                         //DEBUG!!!!!! Hacemos submit intermedio
                    }
                    curso.Facultad = facultad;
                }   //endif (curso == null)

                //Si el curso no tiene secciones, entonces procedemos a agregarlas.    //TODO: Actualizar secciones existentes.
                if (curso.GetSecciones(periodo).Count() == 0)
                {
                    //Recorremos todas las Secciones del XML
                    //foreach (XmlNode seccNode in seccionesNodes)
                    for (XmlNode seccNode = ramoNode["Seccion"]; (seccNode != null) && (seccNode.FirstChild.LocalName == "Profesores"); seccNode = seccNode.NextSibling)
                    {
                        Seccion seccion = new Seccion();
                        seccion.NumSeccion = Int32.Parse(seccNode.Attributes["NumSeccion"].Value);
                        seccion.Curso = curso;
                        seccion.Periodo = periodo;
                        seccion.PuntajeCorte = null;                    //TODO! Agregar ptje de corte
                        seccion.Vacantes = Int32.Parse(seccNode["Vacantes"].InnerText);

                        //Insertamos los profesores:
                        foreach (XmlNode profeNode in seccNode["Profesores"])
                        {
                            string profeNombre = profeNode.InnerText;
                            Profesor profe = repoProfesor.GetProfesor(profeNombre);
                            //Si no existe creamos un profe nuevo:
                            if (profe == null)
                            {
                                profe = new Profesor();
                                profe.NombreProfesor = profeNombre;     //TODO: Asignar depto., correo, etc. al profesor
                                repoProfesor.AddProfesor(profe);
                                db.SubmitChanges();                         //DEBUG!!!!!! Hacemos submit intermedio
                            }

                            //Unimos un profesor con una seccion usando una tabla intermedia    //FIX: Debe haber una forma mas elegante...
                            ProfesorSeccion profeSecRelacion = new ProfesorSeccion();
                            profeSecRelacion.Profesor = profe;
                            profeSecRelacion.Seccion = seccion;

                            db.ProfesorSeccions.InsertOnSubmit(profeSecRelacion);   //Me da lata crear un RepositorioProfeSeccion
                        }
                        
                        //Horario:
                        Horario horario = new Horario();
                        seccion.Horario = horario;
                        horario.ModulosString = seccNode["Horario"].Attributes["ModuloString"].Value;
                        horario.SalasString = seccNode["Horario"].Attributes["SalaString"].Value;

                        //Iteramos por los modulos:
                        foreach (XmlNode moduloNode in seccNode["Horario"])
                        {
                            Modulo mod = new Modulo();
                            mod.DiaSemana = (int)Enum.Parse(typeof(DayOfWeek), moduloNode.Attributes["Dia"].Value);
                            mod.NumModulo = Int32.Parse(moduloNode.Attributes["Mod"].Value);

                            //Agregamos la sala:
                            string salaStr = moduloNode.Attributes["Sala"].Value;
                            string campus = seccNode["Campus"].InnerText;
                            Sala sala = db.Salas.SingleOrDefault(s => s.Nombre == salaStr && s.Campus == campus);     //Me da lata crear un RepositorioSala
                            if (sala == null)
                            {
                                sala = new Sala();
                                sala.Nombre = salaStr;
                                sala.Campus = campus;
                                db.Salas.InsertOnSubmit(sala);
                                db.SubmitChanges();                         //DEBUG!!!!!! Hacemos submit intermedio
                            }
                            
                            //Agregamos el tipo actividad:
                            string actividadStr = moduloNode.Attributes["TipoActividad"].Value;
                            TipoActividad actividad = db.TipoActividads.SingleOrDefault(a => a.Nombre == actividadStr);
                            if (actividad == null)
                            {
                                actividad = new TipoActividad();
                                actividad.Nombre = actividadStr;
                                db.TipoActividads.InsertOnSubmit(actividad);        //Me da lata crear un RepoTipoActividad
                                db.SubmitChanges();                         //DEBUG!!!!!! Hacemos submit intermedio
                            }

                            //Asociamos la sala y actividad al modulo (estas 2 ya fueron agregadas a la DB)
                            mod.Sala = sala;
                            mod.TipoActividad = actividad;

                            db.Modulos.InsertOnSubmit(mod);         //Me da lata crear un RepoModulo
                            horario.Modulos.Add(mod);
                        }
                        //db.Horarios.InsertOnSubmit(horario);        //Me da lata crear un RepositorioHorario
                        //seccion.Horario = horario;

                        //Agregamos las evaluaciones:
                        foreach (XmlNode evalNode in seccNode["Evaluaciones"])          //TODO: Si estamos actualizando, chequear que la evaluacion no existe
                        {
                            Evaluacion evaluacion = new Evaluacion();
                            evaluacion.Nombre = evalNode.Attributes["Nombre"].Value;
                            evaluacion.Fecha = DateTime.Parse(evalNode.InnerText);
                            evaluacion.Seccion = seccion;
                            db.Evaluacions.InsertOnSubmit(evaluacion);      //Me da lata crear un RepoEvaluacion

                            seccion.Evaluaciones.Add(evaluacion);
                            db.SubmitChanges();
                        }

                    }  //foreach seccNode
                }

                //repoCursos.AddCurso(curso);       //??? NO ES NECESARIO HACERLO, AL SUBMITEAR UNA SECCION SE AGREGA EL "ARBOL" COMPLETO DE CLASES

                //db.SubmitChanges();   //guardar dp de cada insercion de ramo?
                //db.Dispose();

            }   //foreach ramoNode..

            //No olvidar guardar los cambios! :)
            Console.WriteLine("Procesados {0} ramos. Procediendo a agregar a la DB...", ramosTotal);
            db.SubmitChanges();
            Console.WriteLine("Transaccion terminada. Tiempo total: {0} segundos.", (DateTime.Now - start).TotalSeconds);
            Console.ReadKey();

        }   //end method
    }
}
